package java基础知识;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author coderFu
 * @create 2022/2/7
 * 双重检测 DCL
 */
public class DoubleCheckLock {

    private static  int  MAX_THREAD_NUM = 10;

    public static void main(String[] args) {
        for (int i = 0; i <MAX_THREAD_NUM ; i++) {
           new Thread(new MyThread()).start();
        }
    }


}

class SingleObject{
    /**
     *
     私有化构造方法，防止客户端用new 进行创建对象
     */
    private SingleObject(){

    }

    private static Lock lock = new ReentrantLock();
    //更安全的做法，在此加上volatile关键字，防止多线程访问造成指令重排序

    private static volatile   SingleObject _singleObject;

    public static SingleObject newInstance() throws Exception{
        if (_singleObject == null){
            System.out.println("我是"+Thread.currentThread().getName()+",单例对象还没有创建");
            //休息一会，模拟多个线程到达这里
            Thread.sleep(1000);
            lock.lock();
            try {
                System.out.println("我是"+Thread.currentThread().getName()+",单例对象还没创建，哈哈，我进来了哈");
                //睡眠一会
                Thread.sleep(1000);
                if (_singleObject == null){
                    _singleObject = new SingleObject();
                    System.out.println("我是"+Thread.currentThread().getName()+",对象是我创建的，承让了");
                }else {
                    System.out.println("我是"+Thread.currentThread().getName()+",虽然我进来了，但是对象已经被别人创建了");
                }
            }finally {
                lock.unlock();
            }
        }
        return _singleObject;
    }


}

class MyThread implements Runnable{


    @Override
    public void run() {
        try {
            SingleObject singleObject = SingleObject.newInstance();
            System.out.println("获取到的单例对象的地址为"+singleObject);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
